﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using StackExchange.Redis;
using StarUtils.Extension;

namespace StarUtils.Cache
{
    public interface ICacheProvider
    {
        string Name { get; }

        bool IsDistributedCache { get; }

        int Order { get; }

        int MaxRdSecond { get; }

        CacheStatsInfo CacheStatsInfo { get; }

        int GetCount(string prefix = "");

        bool Exists(string cacheKey);

        Task<bool> ExistsAsync(string cacheKey);

        IDatabase GetConn();

        CacheValue<string> StringGet(string cacheKey);

        Task<CacheValue<string>> StringGetAsync(string cacheKey);

        double StringSetIncrement(string redisKey, double value);

        Task<double> StringSetIncrementAsync(string redisKey, double value);

        CacheValue<T> Get<T>(string cacheKey);

        Task<CacheValue<T>> GetAsync<T>(string cacheKey);

        CacheValue<T> Get<T>(string cacheKey, Func<T> dataRetriever, TimeSpan expiry) where T : class;

        Task<CacheValue<T>> GetAsync<T>(string cacheKey, Func<Task<T>> dataRetriever, TimeSpan expiry) where T : class;

        IDictionary<string, CacheValue<T>> GetAll<T>(IEnumerable<string> cacheKeys);

        Task<IDictionary<string, CacheValue<T>>> GetAllAsync<T>(IEnumerable<string> cacheKeys);

        IDictionary<string, CacheValue<T>> GetByPrefix<T>(string prefix, string excludeStr = "");

        Task<IDictionary<string, CacheValue<T>>> GetByPrefixAsync<T>(string prefix, string excludeStr = "");

        void Flush();

        Task FlushAsync();

        void Refresh<T>(string cacheKey, T cacheValue, TimeSpan expiry);

        Task RefreshAsync<T>(string cacheKey, T cacheValue, TimeSpan expiry);

        void Remove(string cacheKey);

        Task RemoveAsync(string cacheKey);

        void RemoveByPrefix(string prefix);

        Task RemoveByPrefixAsync(string prefix);

        void RemoveAll(IEnumerable<string> cacheKeys);

        Task RemoveAllAsync(IEnumerable<string> cacheKeys);

        Task StringSetAsync(string cacheKey, string cacheValue, TimeSpan? expiry = null);

        void StringSet(string cacheKey, string cacheValue, TimeSpan? expiry = null);

        void Set<T>(string cacheKey, T cacheValue, TimeSpan expiry);

        Task SetAsync<T>(string cacheKey, T cacheValue, TimeSpan expiry);

        void SetAll<T>(IDictionary<string, T> values, TimeSpan expiry);

        Task SetAllAsync<T>(IDictionary<string, T> values, TimeSpan expiry);

        double? SortedSetGetScored(string redisKey, string member, bool userDefaultKey = true);

        Task<double?> SortedSetGetScoredAsync(string redisKey, string member, bool userDefaultKey = true);

        Task<bool> SortedSetAddAsync(string redisKey, string member, double score, bool userDefaultKey = true);

        bool SortedSetAdd(string redisKey, string member, double score, bool userDefaultKey = true);

        IEnumerable<string> SortedSetRangeByRank(string redisKey, long start = 0L, long stop = -1L, int order = 1, bool userDefaultKey = true);

        Task<IEnumerable<string>> SortedSetRangeByRankAsync(string redisKey, long start = 0L, long stop = -1L, int order = 1, bool userDefaultKey = true);

        Dictionary<string, double> GetSortedWithScore(string cacheKey, long start = 0L, long end = 0L, Order order = StackExchange.Redis.Order.Descending, bool withPefixkey = false);

        Task<Dictionary<string, double>> GetSortedWithScoreAsync(string cacheKey, long start = 0L, long end = 0L, Order order = StackExchange.Redis.Order.Descending, bool withPefixkey = false);

        long SortedSetLength(string redisKey, bool userDefaultKey = false);

        bool SortedSetRemoveMember(string redisKey, string memebr, bool userDefaultKey = true);

        Task<bool> SortedSetRemoveMemberAsync(string redisKey, string memebr, bool userDefaultKey = true);

        double SortedSetIncrement(string redisKey, string member, double value = 1.0, bool userDefaultKey = true);

        Task<double> SortedSetIncrementAsync(string redisKey, string member, double value = 1.0, bool userDefaultKey = true);

        Task<long> HashLengthAsync(string redisKey, bool userDefaultKey = true);

        long HashLength(string redisKey, bool userDefaultKey = true);

        Task<Dictionary<RedisValue, RedisValue>> HashGetAllAsync(string redisKey, bool userDefaultKey = true);

        Dictionary<RedisValue, RedisValue> HashGetAll(string redisKey, bool userDefaultKey = true);

        bool HashSet(string redisKey, string hashField, string value, bool userDefaultKey = true);

        Task<bool> HashSetAsync(string redisKey, string hashField, string value, bool userDefaultKey = true);

        long HashValueIncrement(string redisKey, string hashField, long value, bool userDefaultKey = true);

        Task<long> HashValueIncrementAsync(string redisKey, string hashField, long value, bool userDefaultKey = true);

        bool HashExists(string redisKey, string hashField, bool userDefaultKey = true);

        Task<bool> HashExistsAsync(string redisKey, string hashField, bool userDefaultKey = true);

        bool HashRemoveMember(string redisKey, string hashField, bool userDefaultKey = true);

        Task<bool> HashRemoveMemberAsync(string redisKey, string hashField, bool userDefaultKey = true);

        bool SetExist(string redisKey, string value, bool userDefaultKey = false);

        Task<bool> SetExistAsync(string redisKey, string value, bool userDefaultKey = true);

        Task<IEnumerable<string>> SetGetAllAsync(string redisKey, bool userDefaultKey = false);

        IEnumerable<string> SetGetAll(string redisKey, bool userDefaultKey = false);

        bool SetAdd(string redisKey, string value, bool userDefaultKey = false);

        Task<bool> SetAddAsync(string redisKey, string value, bool userDefaultKey = false);

        bool SetRmoveMember(string redisKey, string value, bool userDefaultKey = false);

        Task<bool> SetRmoveMemberAsync(string redisKey, string value, bool userDefaultKey = false);

        long SetLength(string redisKey, bool userDefaultKey = false);

        Task<long> SetLengthAsync(string redisKey, bool userDefaultKey = false);

        RedisKey[] SearchRedisKeys(string pattern);
    }


    public class RedisCacheProvider : ICacheProvider
    {
        private readonly IDatabase _cache;

        private readonly IEnumerable<IServer> _servers;

        private readonly IRedisDatabaseProvider _dbProvider;

        private readonly ICacheSerializer _serializer;

        private readonly RedisOptions _options;

        public string Name { get; }

        public bool IsDistributedCache => false;

        public int Order => _options.Order;

        public int MaxRdSecond => _options.MaxRdSecond;

        public CacheStatsInfo CacheStatsInfo { get; }

        public static IServiceProvider Instance { get; set; }

        public int MyProperty { get; set; }

        public RedisCacheProvider(IRedisDatabaseProvider dbProvider, ICacheSerializer serializer, IOptionsMonitor<RedisOptions> options)
        {
            _dbProvider = dbProvider;
            _serializer = serializer;
            _options = options.CurrentValue;
            if (!_options.DbConfig.EndPoints.Any())
            {
                string[] array = DbConnetStringFrom.GetRedisConfig("Default:Master:Add:host")?.Split(':');
                _options.DbConfig.EndPoints.Add(new ServerEndPoint
                {
                    Host = array[0],
                    Port = int.Parse(array[1])
                });
            }

            _cache = _dbProvider.GetDatabase();
            _servers = _dbProvider.GetServerList();
            CacheStatsInfo = new CacheStatsInfo();
        }

        public RedisCacheProvider(string name, IEnumerable<IRedisDatabaseProvider> dbProviders, ICacheSerializer serializer, IOptionsMonitor<RedisOptions> options)
        {
            _dbProvider = dbProviders.FirstOrDefault((IRedisDatabaseProvider x) => !x.DbProviderName.IsNull() && x.DbProviderName.Equals(name));
            _serializer = serializer;
            _options = options.CurrentValue;
            _cache = _dbProvider.GetDatabase();
            _servers = _dbProvider.GetServerList();
            CacheStatsInfo = new CacheStatsInfo();
            Name = name;
        }

        public int GetCount(string prefix = "")
        {
            if (prefix.IsEmpty())
            {
                int num = 0;
                {
                    foreach (IServer server in _servers)
                    {
                        num += (int)server.DatabaseSize(_cache.Database);
                    }

                    return num;
                }
            }

            return SearchRedisKeys(prefix).Length;
        }

        public bool Exists(string cacheKey)
        {
            if (cacheKey.IsNullOrWhiteSpace())
            {
                return false;
            }

            cacheKey = PrefixKey(cacheKey);
            return _cache.KeyExists(cacheKey);
        }

        public async Task<bool> ExistsAsync(string cacheKey)
        {
            if (cacheKey.IsNullOrWhiteSpace())
            {
                return false;
            }

            cacheKey = PrefixKey(cacheKey);
            return await _cache.KeyExistsAsync(cacheKey);
        }

        public RedisKey[] SearchRedisKeys(string pattern)
        {
            List<RedisKey> list = new List<RedisKey>();
            foreach (IServer server in _servers)
            {
                list.AddRange(server.Keys(pattern: pattern, database: _cache.Database, pageSize: 10, cursor: 0L));
            }

            return list.Distinct().ToArray();
        }

        public IDatabase GetConn()
        {
            return _cache;
        }

        public CacheValue<string> StringGet(string cacheKey)
        {
            if (!cacheKey.IsNullOrWhiteSpace())
            {
                cacheKey = PrefixKey(cacheKey);
                RedisValue redisValue = _cache.StringGet(cacheKey);
                if (!redisValue.IsNull)
                {
                    return new CacheValue<string>(redisValue, hasvalue: true);
                }

                CacheStatsInfo.OnMiss();
            }

            return CacheValue<string>.NoValue;
        }

        public async Task<CacheValue<string>> StringGetAsync(string cacheKey)
        {
            if (!cacheKey.IsNullOrWhiteSpace())
            {
                cacheKey = PrefixKey(cacheKey);
                RedisValue redisValue = await _cache.StringGetAsync(cacheKey);
                if (!redisValue.IsNull)
                {
                    return new CacheValue<string>(redisValue, hasvalue: true);
                }

                CacheStatsInfo.OnMiss();
            }

            return CacheValue<string>.NoValue;
        }

        public async Task StringSetAsync(string cacheKey, string cacheValue, TimeSpan? expiry = null)
        {
            if (!cacheKey.IsNullOrWhiteSpace() && !cacheValue.IsNullOrWhiteSpace() && (!expiry.HasValue || expiry >= TimeSpan.Zero))
            {
                cacheKey = PrefixKey(cacheKey);
                await _cache.StringSetAsync(cacheKey, cacheValue, expiry);
            }
        }

        public void StringSet(string cacheKey, string cacheValue, TimeSpan? expiry = null)
        {
            if (!cacheKey.IsNullOrWhiteSpace() && !cacheValue.IsNullOrWhiteSpace() && (!expiry.HasValue || expiry >= TimeSpan.Zero))
            {
                cacheKey = PrefixKey(cacheKey);
                _cache.StringSet(cacheKey, cacheValue, expiry);
            }
        }

        public double StringSetIncrement(string redisKey, double value)
        {
            return _cache.StringIncrement(redisKey, value);
        }

        public async Task<double> StringSetIncrementAsync(string redisKey, double value)
        {
            return await _cache.StringIncrementAsync(redisKey, value);
        }

        public CacheValue<T> Get<T>(string cacheKey)
        {
            if (!cacheKey.IsNullOrWhiteSpace())
            {
                cacheKey = PrefixKey(cacheKey);
                RedisValue redisValue = _cache.StringGet(cacheKey);
                if (!redisValue.IsNull)
                {
                    CacheStatsInfo.OnHit();
                    return new CacheValue<T>(_serializer.Deserialize<T>(redisValue), hasvalue: true);
                }

                CacheStatsInfo.OnMiss();
            }

            return CacheValue<T>.NoValue;
        }

        public async Task<CacheValue<T>> GetAsync<T>(string cacheKey)
        {
            if (!cacheKey.IsNullOrWhiteSpace())
            {
                cacheKey = PrefixKey(cacheKey);
                RedisValue redisValue = await _cache.StringGetAsync(cacheKey);
                if (!redisValue.IsNull)
                {
                    CacheStatsInfo.OnHit();
                    return new CacheValue<T>(_serializer.Deserialize<T>(redisValue), hasvalue: true);
                }

                CacheStatsInfo.OnMiss();
            }

            return CacheValue<T>.NoValue;
        }

        public CacheValue<T> Get<T>(string cacheKey, Func<T> dataRetriever, TimeSpan expiry) where T : class
        {
            if (!cacheKey.IsNullOrWhiteSpace() && expiry > TimeSpan.Zero)
            {
                cacheKey = PrefixKey(cacheKey);
                RedisValue redisValue = _cache.StringGet(cacheKey);
                if (!redisValue.IsNull)
                {
                    CacheStatsInfo.OnHit();
                    return new CacheValue<T>(_serializer.Deserialize<T>(redisValue), hasvalue: true);
                }

                T val = ((dataRetriever != null) ? dataRetriever() : null);
                if (val != null)
                {
                    Set(cacheKey, val, expiry);
                    return new CacheValue<T>(val, hasvalue: true);
                }
            }

            return CacheValue<T>.NoValue;
        }

        public async Task<CacheValue<T>> GetAsync<T>(string cacheKey, Func<Task<T>> dataRetriever, TimeSpan expiry) where T : class
        {
            cacheKey = PrefixKey(cacheKey);
            if (!cacheKey.IsNullOrWhiteSpace() && expiry > TimeSpan.Zero)
            {
                RedisValue redisValue = await _cache.StringGetAsync(cacheKey);
                if (!redisValue.IsNull)
                {
                    CacheStatsInfo.OnHit();
                    return new CacheValue<T>(_serializer.Deserialize<T>(redisValue), hasvalue: true);
                }

                T item = await (dataRetriever?.Invoke());
                if (item != null)
                {
                    await SetAsync(cacheKey, item, expiry);
                    return new CacheValue<T>(item, hasvalue: true);
                }
            }

            return CacheValue<T>.NoValue;
        }

        public IDictionary<string, CacheValue<T>> GetAll<T>(IEnumerable<string> cacheKeys)
        {
            Dictionary<string, CacheValue<T>> dictionary = new Dictionary<string, CacheValue<T>>();
            if (cacheKeys.Any() && !cacheKeys.Any((string p) => p.IsNullOrWhiteSpace()))
            {
                cacheKeys = cacheKeys.Select((string p) => PrefixKey(p));
                string[] array = cacheKeys.ToArray();
                RedisValue[] array2 = _cache.StringGet(((IEnumerable<string>)array).Select((Func<string, RedisKey>)((string x) => x)).ToArray());
                for (int i = 0; i < array.Length; i++)
                {
                    RedisValue redisValue = array2[i];
                    if (!redisValue.IsNull)
                    {
                        dictionary.Add(array[i], new CacheValue<T>(_serializer.Deserialize<T>(redisValue), hasvalue: true));
                    }
                    else
                    {
                        dictionary.Add(array[i], CacheValue<T>.NoValue);
                    }
                }
            }

            return dictionary;
        }

        public async Task<IDictionary<string, CacheValue<T>>> GetAllAsync<T>(IEnumerable<string> cacheKeys)
        {
            Dictionary<string, CacheValue<T>> result = new Dictionary<string, CacheValue<T>>();
            if (cacheKeys.Any() && !cacheKeys.Any((string p) => p.IsNullOrWhiteSpace()))
            {
                cacheKeys = cacheKeys.Select((string p) => PrefixKey(p));
                string[] keyArray = cacheKeys.ToArray();
                RedisValue[] array = await _cache.StringGetAsync(((IEnumerable<string>)keyArray).Select((Func<string, RedisKey>)((string x) => x)).ToArray());
                for (int i = 0; i < keyArray.Length; i++)
                {
                    RedisValue redisValue = array[i];
                    if (!redisValue.IsNull)
                    {
                        result.Add(keyArray[i], new CacheValue<T>(_serializer.Deserialize<T>(redisValue), hasvalue: true));
                    }
                    else
                    {
                        result.Add(keyArray[i], CacheValue<T>.NoValue);
                    }
                }
            }

            return result;
        }

        public IDictionary<string, CacheValue<T>> GetByPrefix<T>(string prefix, string excludeStr = "")
        {
            Dictionary<string, CacheValue<T>> dictionary = new Dictionary<string, CacheValue<T>>();
            if (!prefix.IsNullOrWhiteSpace())
            {
                prefix = HandlerPrefix(prefix);
                RedisKey[] array = SearchRedisKeys(prefix);
                if (!excludeStr.IsNullOrWhiteSpace())
                {
                    array = array.Where((RedisKey p) => !p.ToString().Contains(excludeStr)).ToArray();
                }

                RedisValue[] array2 = _cache.StringGet(array).ToArray();
                for (int i = 0; i < array.Length; i++)
                {
                    RedisValue redisValue = array2[i];
                    if (!redisValue.IsNull)
                    {
                        dictionary.Add(array[i], new CacheValue<T>(_serializer.Deserialize<T>(redisValue), hasvalue: true));
                    }
                    else
                    {
                        dictionary.Add(array[i], CacheValue<T>.NoValue);
                    }
                }
            }

            return dictionary;
        }

        public async Task<IDictionary<string, CacheValue<T>>> GetByPrefixAsync<T>(string prefix, string excludeStr)
        {
            Dictionary<string, CacheValue<T>> result = new Dictionary<string, CacheValue<T>>();
            if (!prefix.IsNullOrWhiteSpace())
            {
                prefix = HandlerPrefix(prefix);
                RedisKey[] redisKeys = SearchRedisKeys(prefix);
                if (!excludeStr.IsNullOrWhiteSpace())
                {
                    redisKeys = redisKeys.Where((RedisKey p) => !p.ToString().Contains(excludeStr)).ToArray();
                }

                RedisValue[] array = (await _cache.StringGetAsync(redisKeys)).ToArray();
                for (int i = 0; i < redisKeys.Length; i++)
                {
                    RedisValue redisValue = array[i];
                    if (!redisValue.IsNull)
                    {
                        result.Add(redisKeys[i], new CacheValue<T>(_serializer.Deserialize<T>(redisValue), hasvalue: true));
                    }
                    else
                    {
                        result.Add(redisKeys[i], CacheValue<T>.NoValue);
                    }
                }
            }

            return result;
        }

        public void Set<T>(string cacheKey, T cacheValue, TimeSpan expiry)
        {
            if (!cacheKey.IsNullOrWhiteSpace() && !cacheValue.IsNull() && expiry > TimeSpan.Zero)
            {
                cacheKey = PrefixKey(cacheKey);
                if (MaxRdSecond > 0)
                {
                    int seconds = new Random().Next(1, MaxRdSecond);
                    expiry.Add(new TimeSpan(0, 0, seconds));
                }

                _cache.StringSet(cacheKey, _serializer.Serialize(cacheValue), expiry);
            }
        }

        public async Task SetAsync<T>(string cacheKey, T cacheValue, TimeSpan expiry)
        {
            if (!cacheKey.IsNullOrWhiteSpace() && !cacheValue.IsNull() && expiry > TimeSpan.Zero)
            {
                cacheKey = PrefixKey(cacheKey);
                if (MaxRdSecond > 0)
                {
                    int seconds = new Random().Next(1, MaxRdSecond);
                    expiry.Add(new TimeSpan(0, 0, seconds));
                }

                await _cache.StringSetAsync(cacheKey, _serializer.Serialize(cacheValue), expiry);
            }
        }

        public void SetAll<T>(IDictionary<string, T> values, TimeSpan expiry)
        {
            if (values == null || values.Any() || !(expiry > TimeSpan.Zero))
            {
                return;
            }

            IBatch batch = _cache.CreateBatch();
            foreach (KeyValuePair<string, T> value in values)
            {
                batch.StringSetAsync(PrefixKey(value.Key), _serializer.Serialize(value.Value), expiry);
            }

            batch.Execute();
        }

        public async Task SetAllAsync<T>(IDictionary<string, T> values, TimeSpan expiry)
        {
            if (values == null || values.Any() || !(expiry > TimeSpan.Zero))
            {
                return;
            }

            List<Task> list = new List<Task>();
            foreach (KeyValuePair<string, T> value in values)
            {
                list.Add(SetAsync(PrefixKey(value.Key), value.Value, expiry));
            }

            await Task.WhenAll(list);
        }

        public void Remove(string cacheKey)
        {
            if (!cacheKey.IsNullOrWhiteSpace())
            {
                cacheKey = PrefixKey(cacheKey);
                _cache.KeyDelete(cacheKey);
            }
        }

        public async Task RemoveAsync(string cacheKey)
        {
            if (!cacheKey.IsNullOrWhiteSpace())
            {
                cacheKey = PrefixKey(cacheKey);
                await _cache.KeyDeleteAsync(cacheKey);
            }
        }

        public void RemoveByPrefix(string prefix)
        {
            if (!prefix.IsNullOrWhiteSpace())
            {
                prefix = HandlerPrefix(prefix);
                RedisKey[] keys = SearchRedisKeys(prefix);
                _cache.KeyDelete(keys);
            }
        }

        public async Task RemoveByPrefixAsync(string prefix)
        {
            if (!prefix.IsNullOrWhiteSpace())
            {
                prefix = HandlerPrefix(prefix);
                RedisKey[] keys = SearchRedisKeys(prefix);
                await _cache.KeyDeleteAsync(keys);
            }
        }

        public void RemoveAll(IEnumerable<string> cacheKeys)
        {
            if (cacheKeys != null && cacheKeys.Any())
            {
                RedisKey[] array = cacheKeys.Where((string x) => !string.IsNullOrWhiteSpace(x)).Select((Func<string, RedisKey>)((string p) => PrefixKey(p))).ToArray();
                if (array.Length != 0)
                {
                    _cache.KeyDelete(array);
                }
            }
        }

        public async Task RemoveAllAsync(IEnumerable<string> cacheKeys)
        {
            if (cacheKeys != null && cacheKeys.Any())
            {
                RedisKey[] array = cacheKeys.Where((string x) => !string.IsNullOrWhiteSpace(x)).Select((Func<string, RedisKey>)((string p) => PrefixKey(p))).ToArray();
                if (array.Length != 0)
                {
                    await _cache.KeyDeleteAsync(array);
                }
            }
        }

        public void Refresh<T>(string cacheKey, T cacheValue, TimeSpan expiry)
        {
            if (!cacheKey.IsNullOrWhiteSpace() && !cacheValue.IsNull() && expiry > TimeSpan.Zero)
            {
                Remove(cacheKey);
                Set(cacheKey, cacheValue, expiry);
            }
        }

        public async Task RefreshAsync<T>(string cacheKey, T cacheValue, TimeSpan expiry)
        {
            if (!cacheKey.IsNullOrWhiteSpace() && !cacheValue.IsNull() && expiry > TimeSpan.Zero)
            {
                await RemoveAsync(cacheKey);
                await SetAsync(cacheKey, cacheValue, expiry);
            }
        }

        public void Flush()
        {
            foreach (IServer server in _servers)
            {
                server.FlushDatabase(_cache.Database);
            }
        }

        public async Task FlushAsync()
        {
            List<Task> list = new List<Task>();
            foreach (IServer server in _servers)
            {
                list.Add(server.FlushDatabaseAsync(_cache.Database));
            }

            await Task.WhenAll(list);
        }

        public double? SortedSetGetScored(string redisKey, string member, bool userDefaultKey = true)
        {
            if (redisKey.IsNullOrWhiteSpace() || member.IsNullOrWhiteSpace())
            {
                return null;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return _cache.SortedSetScore(redisKey, member);
        }

        public async Task<double?> SortedSetGetScoredAsync(string redisKey, string member, bool userDefaultKey = true)
        {
            if (redisKey.IsNullOrWhiteSpace() || member.IsNullOrWhiteSpace())
            {
                return null;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return await _cache.SortedSetScoreAsync(redisKey, member);
        }

        public IEnumerable<string> SortedSetRangeByRank(string redisKey, long start = 0L, long stop = -1L, int order = 1, bool userDefaultKey = true)
        {
            if (redisKey.IsNullOrWhiteSpace())
            {
                return null;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return from x in _cache.SortedSetRangeByRank(redisKey, start, stop, (Order)order)
                   select x.ToString();
        }

        public async Task<IEnumerable<string>> SortedSetRangeByRankAsync(string redisKey, long start = 0L, long stop = -1L, int order = 1, bool userDefaultKey = true)
        {
            if (redisKey.IsNullOrWhiteSpace())
            {
                return null;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return (await _cache.SortedSetRangeByRankAsync(redisKey, start, stop, (Order)order)).Select((RedisValue x) => x.ToString());
        }

        public bool SortedSetAdd(string redisKey, string member, double score, bool userDefaultKey = true)
        {
            if (redisKey.IsNullOrWhiteSpace())
            {
                return false;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return _cache.SortedSetAdd(redisKey, member, score);
        }

        public async Task<bool> SortedSetAddAsync(string redisKey, string member, double score, bool userDefaultKey = true)
        {
            if (redisKey.IsNullOrWhiteSpace())
            {
                return false;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return await _cache.SortedSetAddAsync(redisKey, member, score);
        }

        public Dictionary<string, double> GetSortedWithScore(string cacheKey, long start = 0L, long end = 0L, Order order = StackExchange.Redis.Order.Descending, bool withPefixkey = false)
        {
            Dictionary<string, double> result = new Dictionary<string, double>();
            if (!cacheKey.IsNullOrWhiteSpace())
            {
                if (withPefixkey)
                {
                    cacheKey = PrefixKey(cacheKey);
                }

                SortedSetEntry[] array = _cache.SortedSetRangeByRankWithScores(cacheKey, start, end, order);
                if (array != null)
                {
                    result = array.ToStringDictionary();
                }
            }

            return result;
        }

        public async Task<Dictionary<string, double>> GetSortedWithScoreAsync(string cacheKey, long start = 0L, long end = -1L, Order order = StackExchange.Redis.Order.Descending, bool withPefixkey = false)
        {
            Dictionary<string, double> result = new Dictionary<string, double>();
            if (!cacheKey.IsNullOrWhiteSpace())
            {
                if (withPefixkey)
                {
                    cacheKey = PrefixKey(cacheKey);
                }

                SortedSetEntry[] array = await _cache.SortedSetRangeByRankWithScoresAsync(cacheKey, start, end, order);
                if (array != null)
                {
                    result = array.ToStringDictionary();
                }
            }

            return result;
        }

        public long SortedSetLength(string redisKey, bool userDefaultKey = false)
        {
            if (redisKey.IsNullOrWhiteSpace())
            {
                return 0L;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return _cache.SortedSetLength(redisKey);
        }

        public bool SortedSetRemoveMember(string redisKey, string member, bool userDefaultKey = true)
        {
            if (redisKey.IsNullOrWhiteSpace() || member.IsNullOrWhiteSpace())
            {
                return false;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return _cache.SortedSetRemove(redisKey, member);
        }

        public async Task<bool> SortedSetRemoveMemberAsync(string redisKey, string member, bool userDefaultKey = true)
        {
            if (redisKey.IsNullOrWhiteSpace() || member.IsNullOrWhiteSpace())
            {
                return false;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return await _cache.SortedSetRemoveAsync(redisKey, member);
        }

        public double SortedSetIncrement(string redisKey, string member, double value = 1.0, bool userDefaultKey = true)
        {
            if (redisKey.IsNullOrWhiteSpace() || member.IsNullOrWhiteSpace())
            {
                return 0.0;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return _cache.SortedSetIncrement(redisKey, member, value);
        }

        public async Task<double> SortedSetIncrementAsync(string redisKey, string member, double value = 1.0, bool userDefaultKey = true)
        {
            if (redisKey.IsNullOrWhiteSpace() || member.IsNullOrWhiteSpace())
            {
                return 0.0;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return await _cache.SortedSetIncrementAsync(redisKey, member, value);
        }

        public async Task<Dictionary<RedisValue, RedisValue>> HashGetAllAsync(string redisKey, bool userDefaultKey = true)
        {
            if (redisKey.IsNullOrWhiteSpace())
            {
                return new Dictionary<RedisValue, RedisValue>();
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            _cache.HashGetAll(redisKey).ToDictionary();
            return (await _cache.HashGetAllAsync(redisKey)).ToDictionary();
        }

        public async Task<long> HashLengthAsync(string redisKey, bool userDefaultKey = true)
        {
            if (redisKey.IsNullOrWhiteSpace())
            {
                return 0L;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return await _cache.HashLengthAsync(redisKey);
        }

        public long HashLength(string redisKey, bool userDefaultKey = true)
        {
            if (redisKey.IsNullOrWhiteSpace())
            {
                return 0L;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return _cache.HashLength(redisKey);
        }

        public Dictionary<RedisValue, RedisValue> HashGetAll(string redisKey, bool userDefaultKey = true)
        {
            if (redisKey.IsNullOrWhiteSpace())
            {
                return new Dictionary<RedisValue, RedisValue>();
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return _cache.HashGetAll(redisKey).ToDictionary();
        }

        public bool HashSet(string redisKey, string hashField, string value, bool userDefaultKey = true)
        {
            if (redisKey.IsNullOrWhiteSpace())
            {
                return false;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return _cache.HashSet(redisKey, hashField, value);
        }

        public async Task<bool> HashSetAsync(string redisKey, string hashField, string value, bool userDefaultKey = true)
        {
            if (redisKey.IsNullOrWhiteSpace())
            {
                return false;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return await _cache.HashSetAsync(redisKey, hashField, value);
        }

        public long HashValueIncrement(string redisKey, string hashField, long value, bool userDefaultKey = true)
        {
            if (redisKey.IsNullOrWhiteSpace())
            {
                return 0L;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return _cache.HashIncrement(redisKey, hashField, value);
        }

        public async Task<long> HashValueIncrementAsync(string redisKey, string hashField, long value, bool userDefaultKey = true)
        {
            if (redisKey.IsNullOrWhiteSpace())
            {
                return 0L;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return await _cache.HashIncrementAsync(redisKey, hashField, value);
        }

        public bool HashExists(string redisKey, string hashField, bool userDefaultKey = true)
        {
            if (redisKey.IsNullOrWhiteSpace())
            {
                return false;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return _cache.HashExists(redisKey, hashField);
        }

        public async Task<bool> HashExistsAsync(string redisKey, string hashField, bool userDefaultKey = true)
        {
            if (redisKey.IsNullOrWhiteSpace())
            {
                return false;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return await _cache.HashExistsAsync(redisKey, hashField);
        }

        public async Task<bool> HashRemoveMemberAsync(string redisKey, string hashField, bool userDefaultKey = true)
        {
            if (redisKey.IsNullOrWhiteSpace())
            {
                return false;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return await _cache.HashDeleteAsync(redisKey, hashField);
        }

        public bool HashRemoveMember(string redisKey, string hashField, bool userDefaultKey = true)
        {
            if (redisKey.IsNullOrWhiteSpace())
            {
                return false;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return _cache.HashDelete(redisKey, hashField);
        }

        public async Task<bool> SetExistAsync(string redisKey, string value, bool userDefaultKey = false)
        {
            if (redisKey.IsNullOrWhiteSpace() || value.IsNullOrWhiteSpace())
            {
                return false;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return await _cache.SetContainsAsync(redisKey, value);
        }

        public bool SetExist(string redisKey, string value, bool userDefaultKey = false)
        {
            if (redisKey.IsNullOrWhiteSpace() || value.IsNullOrWhiteSpace())
            {
                return false;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return _cache.SetContains(redisKey, value);
        }

        public async Task<IEnumerable<string>> SetGetAllAsync(string redisKey, bool userDefaultKey = false)
        {
            if (redisKey.IsNullOrWhiteSpace())
            {
                return null;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return (await _cache.SetMembersAsync(redisKey)).Select((RedisValue p) => p.ToString());
        }

        public IEnumerable<string> SetGetAll(string redisKey, bool userDefaultKey = false)
        {
            if (redisKey.IsNullOrWhiteSpace())
            {
                return null;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return from p in _cache.SetMembers(redisKey)
                   select p.ToString();
        }

        public async Task<bool> SetAddAsync(string redisKey, string value, bool userDefaultKey = false)
        {
            if (redisKey.IsNullOrWhiteSpace() || value.IsNullOrWhiteSpace())
            {
                return false;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return await _cache.SetAddAsync(redisKey, value);
        }

        public bool SetAdd(string redisKey, string value, bool userDefaultKey = false)
        {
            if (redisKey.IsNullOrWhiteSpace() || value.IsNullOrWhiteSpace())
            {
                return false;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return _cache.SetAdd(redisKey, value);
        }

        public bool SetRmoveMember(string redisKey, string value, bool userDefaultKey = false)
        {
            if (redisKey.IsNullOrWhiteSpace() || value.IsNullOrWhiteSpace())
            {
                return false;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return _cache.SetRemove(redisKey, value);
        }

        public async Task<bool> SetRmoveMemberAsync(string redisKey, string value, bool userDefaultKey = false)
        {
            if (redisKey.IsNullOrWhiteSpace() || value.IsNullOrWhiteSpace())
            {
                return false;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return await _cache.SetRemoveAsync(redisKey, value);
        }

        public long SetLength(string redisKey, bool userDefaultKey = false)
        {
            if (redisKey.IsNullOrWhiteSpace())
            {
                return 0L;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return _cache.SetLength(redisKey);
        }

        public async Task<long> SetLengthAsync(string redisKey, bool userDefaultKey = false)
        {
            if (redisKey.IsNullOrWhiteSpace())
            {
                return 0L;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return await _cache.SetLengthAsync(redisKey);
        }

        public long ListRightPush(string redisKey, string redisValue, bool userDefaultKey = true)
        {
            if (redisKey.IsNullOrWhiteSpace() || redisValue.IsNullOrWhiteSpace())
            {
                return 0L;
            }

            redisKey = (userDefaultKey ? PrefixKey(redisKey) : redisKey);
            return _cache.ListRightPush(redisKey, redisValue);
        }

        private string HandlerPrefix(string prefix)
        {
            if (prefix.Trim().Equals("*"))
            {
                throw new ArgumentException("前缀不能等于 * ");
            }

            prefix = new Regex("^\\*+").Replace(prefix, "");
            if (!prefix.EndsWith("*", StringComparison.InvariantCultureIgnoreCase))
            {
                prefix += "*";
            }

            prefix = PrefixKey(prefix);
            return prefix;
        }

        private string PrefixKey(string key)
        {
            if (!_options.PrefixName.IsNullOrWhiteSpace())
            {
                return $"{_options.PrefixName}:{key}";
            }

            return key;
        }
    }
}
